using System;
using System.Data;
using System.Configuration;
using System.Collections.Generic;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using TanashCMS.Business.Utilities;
using TanashCMS.Business;
using System.IO;
using System.Xml;
using System.Xml.Xsl;
using System.Xml.XPath;
using System.Text;
using NHibernate;
using System.Web.Profile;

/// <summary>
/// Summary description for CMSPageBase
/// </summary>
public class CMSPageBase : System.Web.UI.Page
{
    XsltArgumentList xArguments = null;
    XslCompiledTransform xPageTransform = null; 
    protected TanashCustomer mCustomer = null;
    protected TanashWebsite mWebsite = null;
    public TanashWebsite Website { get { return mWebsite; } }
    public TanashCustomer Customer { get { return mCustomer; } }
    protected CMSMasterPageBase CMSMasterPage { get { return ((CMSMasterPageBase)Master); } }
    protected Dictionary<string, string> mOptions = new Dictionary<string, string>();

    protected WebPage mCurrentPage = null;

    protected readonly string KEY_TANASH_WEBSITE = "TanashCMSWebsite";

    // website/page data
    protected System.Xml.XmlDocument xDoc = null;
    protected System.Xml.XPath.XPathNavigator xNav = null;
    protected System.Xml.XPath.XPathNavigator xContentNode = null;// the node of the content, if we can find a match
    protected string PageGuid = "";
    protected string PageID="";
    protected string PageTypeID = "";
    protected CMSObjectType PageObjectType = (CMSObjectType)0;
    protected string PageTemplatePath = "";
    protected PageTemplateType TemplateType = PageTemplateType.MasterPage;

    public CMSPageBase()
    {
        //
        // TODO: Add constructor logic here
        //
    }

    protected override void OnPreInit(EventArgs e)
    {
        // determine what website this is based on the hostname
        HttpContext context = HttpContext.Current;
        Uri uri = context.Request.Url;

        // find the hostname
        string[] domain = uri.Host.Split('.');
        string hostname = uri.Host;
        if (hostname.Substring(0, 4) == "www.")
            hostname = hostname.Substring(4);

        // see if the website is already cached
        if (/*context.Items[KEY_TANASH_WEBSITE] == null && */!(Page is CMSManagementPageBase))
        {
            // not cached - discover the website by the hostname
            mWebsite = TanashWebsite.GetByHostName(hostname);

            context.Items[KEY_TANASH_WEBSITE] = mWebsite;
        }
        else if (Page is CMSManagementPageBase) // or else see if the current user is already tied to a website (not anonymous)
        {
            MembershipUser user = (Membership.GetUser());
            if (user != null)
            {
				ProfileBase prof = ProfileBase.Create(user.UserName,true);
                mWebsite = Configuration.GetCurrentSession().Get<TanashWebsite>(prof.GetPropertyValue("WebsiteID") ?? 9);
            }
            return;
        }
        else if (context.Items[KEY_TANASH_WEBSITE] != null)// must be cached. use the cached value.
            mWebsite = (TanashWebsite)context.Items[KEY_TANASH_WEBSITE];
        else
            mWebsite = (TanashWebsite)Configuration.GetCurrentSession().CreateQuery("select w from TanashWebsite w where w.SubFolderName = 'tanash'").UniqueResult();

        if (mWebsite != null)
        {
            // load any options for this website
            List<WebsiteOption> websiteoptions = (List<WebsiteOption>)Configuration.GetCurrentSession().CreateQuery("select wo from WebsiteOption wo where wo.WebsiteID = " + mWebsite.ID.ToString()).List<WebsiteOption>();
            foreach (WebsiteOption option in websiteoptions)
                mOptions.Add(option.OptionTitle, option.OptionValue);
            websiteoptions = null;

            // load the data for the object we're looking at
            bool noProblem = true;
            if (Cache.Get("xml_" + mWebsite.SubFolderName) == null)
            {
                string xmlUri = Web2Xml.getWebsiteXml(mWebsite.ID);
                try
                {
                    xDoc = new XmlDocument();
                    xDoc.Load(Server.MapPath(xmlUri));
                }
                catch (Exception ex)
                {
                    noProblem = false;
                }

                if (noProblem)
                    Cache.Add("xml_" + mWebsite.SubFolderName, xDoc, new System.Web.Caching.CacheDependency(Server.MapPath(xmlUri)), System.Web.Caching.Cache.NoAbsoluteExpiration, TimeSpan.FromSeconds(30), System.Web.Caching.CacheItemPriority.Normal, null);
            }
            else
                xDoc = (XmlDocument)Cache.Get("xml_" + mWebsite.SubFolderName);

            PageObjectType = CMSObjectType.WebPage;
            PageTemplatePath = Path.Combine(mWebsite.TemplatesFolder, mWebsite.DefaultTemplate).Replace("\\", "/");
            if (Request.QueryString["guid"] != null)
            {
                string id = Request.QueryString["guid"];
                PageGuid = id.Substring(2);
                PageTypeID = id.Substring(0, 2);
                if (Enum.IsDefined(typeof(CMSObjectType), int.Parse(PageTypeID)))
                    PageObjectType = (CMSObjectType)Enum.Parse(typeof(CMSObjectType), int.Parse(PageTypeID).ToString());
                else // if no type specified assume it's a web page
                    PageObjectType = CMSObjectType.WebPage;
                mCurrentPage = WebPage.getByGUID<WebPage>(PageGuid);
                PageTemplatePath = Path.Combine(mWebsite.TemplatesFolder, xContentNode.GetAttribute("masterPage", "")).Replace("\\", "/");
            }
            else if (Context.Items["pageXPath"] != null)
            {
                string contentXPath = "";
                string[] pitems = ((string)Context.Items["pageXPath"]).Split('/');

                // a product should be in the format /category/category/product
                List<string> contentPathList = new List<string>(); // this is just to make resizing the path array easier
                string[] contentPath = new string[pitems.Length - 1];
                for (int i = 0; i < pitems.Length; i++)
                    if (pitems[i].Trim() != string.Empty) contentPathList.Add(pitems[i].Trim());

                contentPath = contentPathList.ToArray();

                // check for a matching webpage, url format will be /default.html or /about/aboutus.html
                XPathNavigator xNav = xDoc.CreateNavigator();
                //contentXPath = "/website"+generateXPathFromArray(pitems, "webpage", 0);
                contentXPath = new TanashCMS.Business.Task.UrlRewriterTask().ConvertToXPath(Request.Url, CMSObjectType.WebPage);
                xContentNode = xNav.SelectSingleNode(contentXPath);

                if (xContentNode != null && xContentNode.IsNode)
                {
                    PageGuid = xContentNode.GetAttribute("guid", "");
                    PageID = xContentNode.GetAttribute("id", "");
                    PageTemplatePath = Path.Combine(mWebsite.TemplatesFolder, xContentNode.GetAttribute("masterPage", "")).Replace("\\", "/");
                    PageTypeID = ((int)CMSObjectType.WebPage).ToString().PadLeft(2,'0');
                }

                // blog post
                if (xContentNode == null || !xContentNode.IsNode)
                {
                    // check for a product, format will be something like /furniture/chairs/wooden/specialchair.html
                    //contentXPath = "/website/inventory" + generateXPathFromArray(contentPath, "category", 1) + string.Format("/product[@key='{0}']", pitems[pitems.Length - 1]);
                    contentXPath = new TanashCMS.Business.Task.UrlRewriterTask().ConvertToXPath(Request.Url, CMSObjectType.BlogPost);
                    xContentNode = xNav.SelectSingleNode(contentXPath);
                    if (xContentNode != null && xContentNode.IsNode)
                    {
                        PageGuid = xContentNode.GetAttribute("guid", "");
                        PageID = xContentNode.GetAttribute("id", "");
                        PageTypeID = ((int)CMSObjectType.BlogPost).ToString().PadLeft(2, '0');
                        PageTemplatePath = Path.Combine(mWebsite.TemplatesFolder, xContentNode.GetAttribute("masterPage", "")).Replace("\\", "/");
                        PageObjectType = CMSObjectType.BlogPost;
                    }

                }

                // product
                if (xContentNode == null || !xContentNode.IsNode)
                {
                    // check for a product, format will be something like /furniture/chairs/wooden/specialchair.html
                    //contentXPath = "/website/inventory" + generateXPathFromArray(contentPath, "category", 1) + string.Format("/product[@key='{0}']", pitems[pitems.Length - 1]);
                    contentXPath = new TanashCMS.Business.Task.UrlRewriterTask().ConvertToXPath(Request.Url, CMSObjectType.Product);
                    xContentNode = xNav.SelectSingleNode(contentXPath);
                    if (xContentNode != null && xContentNode.IsNode)
                    {
                        PageGuid = xContentNode.GetAttribute("guid", "");
                        PageID = xContentNode.GetAttribute("id", "");
                        PageTypeID = ((int)CMSObjectType.Product).ToString().PadLeft(2, '0');
                        PageObjectType = CMSObjectType.Product;
                    }

                }

                // category
                if (xContentNode == null || !xContentNode.IsNode)
                {
                    // check for a category, format will be something like /furniture/chairs/wooden/default.html
                    //contentXPath = "/website/inventory" + generateXPathFromArray(contentPath, "category", 0);
                    contentXPath = new TanashCMS.Business.Task.UrlRewriterTask().ConvertToXPath(Request.Url, CMSObjectType.Category);
                    xContentNode = xNav.SelectSingleNode(contentXPath);
                    if (xContentNode != null && xContentNode.IsNode)
                    {
                        PageGuid = xContentNode.GetAttribute("guid", "");
                        PageID = xContentNode.GetAttribute("id", "");
                        PageTypeID = ((int)CMSObjectType.Category).ToString().PadLeft(2, '0');
                        PageObjectType = CMSObjectType.Category;
                    }
                }

                if (xContentNode != null)
                    mCurrentPage = WebPage.getByGUID<WebPage>(int.Parse(xContentNode.GetAttribute("id", "")));

            }

            HttpContext.Current.Trace.Write("1");
            if (noProblem)
            {
                xNav = xDoc.CreateNavigator();

                if (PageObjectType == CMSObjectType.WebPage || PageObjectType == CMSObjectType.BlogPost)
                {
                    HttpContext.Current.Trace.Write("2");
                    if (xContentNode == null || !xContentNode.IsNode)
                        xContentNode = xNav.SelectSingleNode("/website/webpage[('" + PageGuid + "'='' and @homepage='1') or ('" + PageID + "'=@id)]");

                    if (xContentNode != null && xContentNode.IsNode)
                    {
                        mCurrentPage = WebPage.getByGUID<WebPage>(int.Parse(xContentNode.GetAttribute("id", "")));

                        string pageTemplateName = xContentNode.GetAttribute("masterPage", "");
                        TemplateType = PageTemplateType.XSLT;
                        HttpContext.Current.Trace.Write("3:" + pageTemplateName);
                        PageTemplatePath = Path.Combine(mWebsite.TemplatesFolder, pageTemplateName).Replace("\\", "/");

                        if (xContentNode.HasAttributes && xContentNode.GetAttribute("secure", "") == "1" && !Page.User.Identity.IsAuthenticated && Path.GetFileNameWithoutExtension(Request.Url.AbsolutePath) != "signin")
                            System.Web.Security.FormsAuthentication.RedirectToLoginPage();
                    }
                }
                else
                {
                    HttpContext.Current.Trace.Write("4:" + mWebsite.DefaultTemplate);
                    PageTemplatePath = Path.Combine(mWebsite.TemplatesFolder, mWebsite.DefaultTemplate).Replace("\\",
                                                                                                                "/");
                }
            }
        }
        base.OnPreInit(e);
    }

    protected override void OnInit(EventArgs e)
    {
        if (!(Page is CMSManagementPageBase))
        {
            TanashCMS.Business.Task.TemplateTask template;
            if (!PageGuid.Equals(string.Empty))
                template = new TanashCMS.Business.Task.TemplateTask(PageID, PageTemplatePath, Request.Url, mWebsite,
                                                                    PageObjectType);
            else
                template = new TanashCMS.Business.Task.TemplateTask(Request.Url, PageTemplatePath, mWebsite);

            template.Process(Response.OutputStream, Request.QueryString, xNav);
        }
        base.OnInit(e);
    }

    protected override void Render(HtmlTextWriter writer)
    {
        if (mWebsite != null && Page.Header != null)
            Page.Title = mWebsite.Title;

        base.Render(writer);
    }

    protected void BindNavigationMenu(Menu NavigationMenu)
    {
        if (mWebsite == null)
            return;
        NavigationMenu.Items.Clear();
        List<Navigation> navItems = (List<Navigation>)Configuration.GetCurrentSession().CreateQuery("select nav from Navigation nav where nav.Website.ID = " + mWebsite.ID.ToString() + " and nav.ParentID = 0 order by nav.ID").List<Navigation>();
        foreach (Navigation nav in navItems)
        {
            MenuItem menuItem = new MenuItem();
            TreeNode node = new TreeNode();
            menuItem.Text = nav.Title;
            menuItem.Value = nav.ID.ToString();
            menuItem.NavigateUrl = nav.NavigateURL;
            menuItem.Target = "_blank";
            BindMenuChildren(menuItem);

            NavigationMenu.Items.Add(menuItem);
        }
    }

    private void BindMenuChildren(MenuItem ParentItem)
    {
        List<Navigation> navItems = (List<Navigation>)Configuration.GetCurrentSession().CreateQuery("select nav from Navigation nav where nav.ParentID = " + ParentItem.Value + " and nav.Website.ID = " + mWebsite.ID.ToString() + " order by nav.ID").List<Navigation>();
        foreach (Navigation nav in navItems)
        {
            MenuItem menuItem = new MenuItem();
            TreeNode node = new TreeNode();
            menuItem.Text = nav.Title;
            menuItem.Value = nav.ID.ToString();
            menuItem.NavigateUrl = nav.NavigateURL;
            menuItem.Target = "_blank";
            BindMenuChildren(menuItem);
            ParentItem.ChildItems.Add(menuItem);
        }
    }

    public static void sendExceptionEmail(Exception exception)
    {
        Exception ex = exception;
        System.Net.Mail.SmtpClient smtp = new System.Net.Mail.SmtpClient(System.Configuration.ConfigurationManager.AppSettings["SMTPHost"]);
        smtp.DeliveryMethod = System.Net.Mail.SmtpDeliveryMethod.Network;

        System.Net.Mail.MailMessage mailmessage = new System.Net.Mail.MailMessage();
        mailmessage.Subject = "Exception:" + HttpContext.Current.Request.Url.Host + " " + HttpContext.Current.Request.Url.AbsoluteUri;

        int intExceptionLevel = 0;
        StringBuilder objSB = new StringBuilder();

        objSB.AppendLine("Error details provided by Global.asax");
        objSB.Append("-----------------" + System.DateTime.Now.ToString() + "-----------------\r\n");
        if (HttpContext.Current.Session != null)
            objSB.Append("SessionID:" + HttpContext.Current.Session.SessionID + "\r\n");
        else
            objSB.Append("No session information (OnPreInit?)\r\n");
        /*MembershipUser user = Membership.GetUser();
        if (user != null && User.Identity.IsAuthenticated)
        {
            objSB.AppendLine("User: " + user.UserName);
            objSB.AppendLine("Profile settings:");
                ProfileBase profile = ProfileBase.GetProfile(user.UserName);
                foreach (SettingsProperty prop in Profile.Properties)
                {
                    objSB.AppendLine(prop.Name + " = " + profile.GetPropertyValue(prop.Name));
                }
            }
            catch (Exception exceptionProfile)
            {
                objSB.AppendLine("Could not retrieve profile settings:");
                objSB.AppendLine(exceptionProfile.Message);
            }
            objSB.AppendLine();
        }*/
        objSB.Append("Form Data: ");

        if (HttpContext.Current.Request.Form.Count == 0)
            objSB.Append("No form data.");

        objSB.Append("\r\n");
        foreach (string key in HttpContext.Current.Request.Form.AllKeys)
            objSB.Append("\t" + key);

        List<Exception> exceptions = new List<Exception>();

        while (true)
        {
            exceptions.Add(ex);

            if (ex.InnerException == null)
                break;

            // get the next exception to log
            ex = ex.InnerException;
        }

        if (exceptions.Count > 0)
        {
            for (int i = exceptions.Count - 1; i >= 0; i--)
            {
                ex = exceptions[i];
                // is this the 1st, 2nd, etc exception in the hierarchy
                intExceptionLevel = i + 1;
                objSB.AppendLine(intExceptionLevel.ToString() + ": Error Description:" + ex.Message);
                objSB.AppendLine(intExceptionLevel.ToString() + ": Source:" + ex.Source.Replace("\r\n", "\r\n" + intExceptionLevel.ToString() + ": "));
                objSB.AppendLine(intExceptionLevel.ToString() + ": Stack Trace:" + ex.StackTrace.Replace("\r\n", "\r\n" + intExceptionLevel.ToString() + ": "));
                objSB.AppendLine(intExceptionLevel.ToString() + ": Target Site:" + ex.TargetSite.Name.Replace("\r\n", "\r\n" + intExceptionLevel.ToString() + ": "));
                objSB.AppendLine();
            }
        }

        mailmessage.Body = objSB.ToString();

        mailmessage.To.Add(new System.Net.Mail.MailAddress("webmaster@tanash.net", "Andrew Myhre"));

        mailmessage.IsBodyHtml = false;

        try
        {
            smtp.Send(mailmessage);
        }
        catch (Exception mailException)
        {
            // can't send emails i guess
            log4net.LogManager.GetLogger("General").Error("Error sending email", mailException);
        }

        // also log the exception info to a text file
        log4net.LogManager.GetLogger("General").Error(objSB.ToString(), exception);
    }

    private string generateXPathFromArray(string[] pitems, string contentType, int TrimCount)
   {
       string contentXPath = "";
       foreach (string p in pitems)
       {
           if (p.Length == 0 || TrimCount++ >= pitems.Length)
               continue;

           contentXPath += string.Format("/{0}[@key='{1}']", contentType, p);
       }

       return contentXPath;
   }

    public string StartRoundCorner()
    {
        return "<div style=\"margin-bottom:6px;\">\r\n" +
          "<b class=\"rc\">\r\n" +
          "<b class=\"rc1\"><b></b></b>\r\n" +
          "<b class=\"rc2\"><b></b></b>\r\n" +
          "<b class=\"rc3\"></b>\r\n" +
          "<b class=\"rc4\"></b>\r\n" +
          "<b class=\"rc5\"></b></b>\r\n\r\n" +
          "<div class=\"rcfg\">";
    }

    public string EndRoundCorner()
    {
        return "</div>\r\n" +
      "<b class=\"rc\">\r\n" +
      "<b class=\"rc5\"></b>\r\n" +
      "<b class=\"rc4\"></b>\r\n" +
      "<b class=\"rc3\"></b>\r\n" +
      "<b class=\"rc2\"><b></b></b>\r\n" +
      "<b class=\"rc1\"><b></b></b></b>\r\n" +
      "<div/>\r\n";
    }

    public string GetCurrencySymbol()
    {
        HttpRequest Request = HttpContext.Current.Request;
        if (Request.UserLanguages == null)
            return "";

        string Lang = Request.UserLanguages[0];
        if (Lang != null)
        {
            if (Lang.Length < 3)
                Lang = Lang + "-" + Lang.ToUpper();

            try
            {
                //System.Threading.Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo(Lang);
                return new System.Globalization.CultureInfo(Lang).NumberFormat.CurrencySymbol;
            }
            catch
            { ;}
        }
        return "";
    }


    protected string GeneratePageXHTMLContent(string transformPath, string guid, XPathNavigator navigator)
    {
        // generate the page content
        string xhtmlContent = "";
        XsltSettings settings = new XsltSettings(false, true);
        XsltArgumentList xContentArguments = new XsltArgumentList();
        StringBuilder sbContent = new StringBuilder();
        StringWriter swContent = new StringWriter(sbContent);

        string xmlUri = Web2Xml.getWebsiteXml(((CMSPageBase)Page).Website.ID);
        xPageTransform = new XslCompiledTransform();

        xContentArguments.AddParam("rootUrl", "", Request.ApplicationPath.TrimEnd('/') + "/");
        xContentArguments.AddParam("guid", "", guid);
        if (mWebsite.SubFolderName == "collisstudios") // TODO: fix this awful hack
        {
            xContentArguments.AddParam("desiredThumbnailWidth", "", 150);
            xContentArguments.AddParam("desiredThumbnailHeight", "", 150);
        }

        xPageTransform.Load(transformPath, settings, new XmlUrlResolver());

        xPageTransform.Transform(navigator, xContentArguments, swContent);
        swContent.Close();

        xhtmlContent = Server.HtmlDecode(Server.HtmlDecode(swContent.ToString()));
        xhtmlContent = ReplacePaths(xhtmlContent);

        return xhtmlContent;
    }

    protected string xhtmlContent = "";

    protected void WritePage(Stream outputStream)
    {
        // generate content for category or product
        if (PageObjectType == CMSObjectType.Category)
            xhtmlContent = GeneratePageXHTMLContent(Server.MapPath(Request.ApplicationPath) + "\\xsl\\category.xsl", PageGuid, xNav);
        else if (PageObjectType == CMSObjectType.Product)
            xhtmlContent = GeneratePageXHTMLContent(Server.MapPath(Request.ApplicationPath) + "\\xsl\\product.xsl", PageGuid, xNav);
        else if (Path.GetFileName(Request.PhysicalPath) == "contact.aspx")
            xhtmlContent = GeneratePageXHTMLContent(Server.MapPath(Request.ApplicationPath) + "\\xsl\\contact.xsl", PageGuid, xNav);

        // generate the page template
        StringBuilder sb = new StringBuilder();
        StringWriter sw = new StringWriter(sb);
        xArguments = new XsltArgumentList();
        xArguments.AddParam("guid", "", PageGuid);
        string xTransform = Server.MapPath(Request.ApplicationPath) + "\\xsl\\webpage-standard.xsl";

        if (PageTemplatePath != "" && Path.GetExtension(PageTemplatePath) == ".xsl")
            xTransform = Server.MapPath(Request.ApplicationPath.TrimEnd('/') + PageTemplatePath); // determined in CMSPageBase OnPreInit
        else
            xTransform = Server.MapPath(Request.ApplicationPath.TrimEnd('/') + mWebsite.DefaultTemplate);

        xArguments.AddParam("currentUrl", "", Request.ApplicationPath.TrimEnd('/') + "/" + Request.Url.Query);
        if (xhtmlContent.Length > 0)
            xArguments.AddParam("xhtmlContent", "", xhtmlContent);
        else
            xArguments.AddParam("xhtmlContent", "", "-");

        if (xContentNode != null)
        {
            if (xContentNode.GetAttribute("homepage", "") == "1")
                xArguments.AddParam("showIndex", "", Website.getOptionValue("ShowIndexOnHomePage"));
            else
                xArguments.AddParam("showIndex", "", Website.getOptionValue("ShowIndexOnWebPages"));
        }

        if (Website.getOptionValue("IsBlogSite") != null && Website.getOptionValue("IsBlogSite") == "1")
        {
            if (Request.QueryString["from"] != null)
                xArguments.AddParam("from", "", Request.QueryString["from"]);
        }

        mCustomer = mWebsite.Customer;

        XsltSettings settings = new XsltSettings(false, true);

        //context.Response.Write("website is " + website.Title + "<br/>");
        string xmlUri = Web2Xml.getWebsiteXml(((CMSPageBase)Page).Website.ID);
        xPageTransform = new XslCompiledTransform();

        xPageTransform.Load(xTransform, settings, new XmlUrlResolver());

        xPageTransform.Transform(xNav, xArguments, sw);
        sw.Close();

        string xhtml = Server.HtmlDecode(Server.HtmlDecode(sw.ToString()));
        xhtml = ReplacePaths(xhtml);

        StreamWriter writer = new StreamWriter(outputStream);
        writer.Write(xhtml);
        writer.Dispose();
    }

    protected string ReplacePaths(string xhtml)
    {
        if (mCurrentPage != null)
            xhtml = xhtml.Replace("@templatepath@", mWebsite.TemplatesFolder + "/" + mCurrentPage.MasterPage);
        else
            xhtml = xhtml.Replace("@templatepath@", mWebsite.TemplatesFolder + "/" + mWebsite.DefaultTemplate);

        return xhtml;
    }

}
